Programmazione avanzata

Un altro programma

Ecco un programma leggermente più complicato; inseritelo in un file e salvatelo col nome addition.cob.

       IDENTIFICATION DIVISION.
       PROGRAM-ID.    addition.
       ENVIRONMENT DIVISION.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       77  myvar PIC 999 .
       77  a  PIC 99V999 VALUE 1.777 .
       77  b  PIC 99V99  VALUE ZERO .
       77  c  PIC 9V9    VALUE 5.5 .
       77  d  PIC 9v9    VALUE 5.5 .
          
       PROCEDURE DIVISION.
           DISPLAY "Inserite un numero"
           ACCEPT myvar
           DISPLAY "Il numero è ", myvar
           ADD a TO b ROUNDED
           DISPLAY "b è ", b
           ADD c TO d
           DISPLAY "d è ", d
           STOP RUN.

Potete compilare questo programma con lo stesso procedimento seguito per hello.cob e, se incontrate un qualche Segmentation Fault, controllate bene il vostro programma prima di reclamare.

Se siete a digiuno di Cobol, notate che vi troverete un inghippo. Inizialmente abbiamo dichiarato alcune variabili nella WORKING-STORAGE SECTION della DATA DIVISION. Il Cobol impone che tutte le variabili siano dichiarate in questa maniera. Le altre sezioni della DATA DIVISION si occupano dei file e dei link.

Tutte le dichiarazioni di variabile iniziano, in questo programma, con `77'. Si intende che la variabile è posta al livello 77: non ha struttura interna e non è definita alcuna relazione con le altre variabili, inoltre non fa parte di un record (che in C corrisponde a una struct). Il nome della prima variabile è myvar; i nomi delle variabili possono essere sia in lettere maiuscole che in lettere minuscole, ma con Tiny Cobol dovete mantenere coerenza in tutto il programma.

La clausola PIC specifica il tipo di variabile. Con i numeri 9 si intende che la variabile è un decimale, e utilizzando tre numeri 9 si ottiene una variabile che può assumere i valori da 0 a 999. Ci può anche essere una `S' prima dei numeri 9, e ciò attribuisce il segno alla variabile. Una `V' nella dichiarazione PIC significa che la variabile riserva una virgola decimale nella posizione con la V. Per variabili di grandi dimensioni si può scrivere 9(15), che è una variabile con 15 posizioni. L'impiego delle lettere A al posto dei numeri 9 trasforma la variabile in alfabetica, e utilizzando le X la variabile diventa alfanumerica. Infine, con VALUE può essere assegnato un valore iniziale alla variabile.

I programmatori non avvezzi al Cobol potrebbero rimanere stupiti di come venga segnalata la conclusione di un'istruzione. La fine di un blocco di codice viene indicata con un punto, e le istruzioni non sono segnalate in alcun modo, mentre invece il compilatore Cobol riconosce l'inizio di una nuova istruzione quando incontra una delle tante parole caratteristiche del Cobol. La fine di una riga non è importante in Cobol. Un'altra cosa da notare nel codice qua sopra, sono le virgole aggiuntive, Le virgole sono del tutto facoltative in Cobol e potete metterle ovunque vogliate (anche da nessuna parte): non fa differenza. Usatele con parsimonia e manterrete il programma più ordinato.

Quando lanciate il programma vi viene chiesto un numero, che poi viene stampato insieme ai risultati dei due calcoli. Il numero dato non può occupare uno spazio maggiore delle 3 posizioni allocategli, in caso contrario vengono accettate solo le ultime tre cifre. Se vengono forniti meno di tre caratteri, il numero verrà stampato con degli zeri iniziali. L'uso dei caratteri non numerici condurrà all'emissione di un qualche codice d'errore.

La somma delle variabili a e b dovrebbe essere effettuata correttamente, e comunque vedrete che il risultato viene arrotondato come da noi desiderato (mediante ROUNDED, ndT). la somma di c con d non produrrà nulla, infatti il risultato è troppo grande perche sia ospitato dalla variable d. Provate a cambiare c in 1.5, ad esempio, e tutto andrà bene.

Make

A questo punto potreste anche esservi un po' stancati della sequenza htcobol, as, e gcc. Ebbene, c'è un modo migliore di procedere, con make. Make prende in input un file chiamato Makefile, e ne usa le istruzioni contenute per effettuare in un colpo solo tutte le compilazioni che servono. Inoltre, make controlla che un file non debba essere compilato prima di fare qualche altra cosa; se nessuna delle dipendenze del programma è cambiata dal'ultima compilazione, non viene effettuato nulla.

Le regole del makefile sono della forma:

obiettivo:dipendenze
	  comando

L'obiettivo (che deve iniziare in prima colonna) è il file che volete ottenere. Le dipendenze sono i file che da cui esso dipende. Il comando (che deve trovarsi sulla seconda riga e deve essere preceduto da un tab) è quello che verrebbe solitamente immesso dalla shell per fabbricare il vostro file. Ecco qui un Makefile per il programma addition:

#un semplice makefile per un programma cobol composto da un singolo file

addition:addition.o
	gcc -o addition addition.o -lhtcobol -lm

addition.o:addition.s
	as -o addition addition.s

addition.s:addition.cob
	htcobol addition

Salvate questo file col nome 'Makefile' nella stessa directory di addition.cob, e digitate 'make': questo comando compila, assembla e linka tutto al posto vostro.

Come comportamento predefinito, make effettua la compilazione del file relativo alla prima regola presente nel Makefile, così da produrre il binario di addition; ma questo file dipende da addition.o, che così deve essere creato prima. addition.o dipende da addition.s, e questo è il primo comando che make esegue. Ora può essere creato addition.o, e infine addition.o viene compilato per creare addition. Se provate a eseguire nuovamente make, non succederà nulla; in effetti, poiché nessuno dei file ha subìto modifiche, make non ha nessun compito da svolgere (e questo, make lo determina consultando la data dell'ultimo salvataggio dei file). Fate una qualche modifica ad addition.cob, ed eseguite make: verrà ripetuto l'intero procedimento.

Uso avanzato di make

Il precedente Makefile, però, ha un problema: come si fa a trasformarlo per fargli compilare un altro programma? Nel nostro caso vanno sostituiti solo alcuni "addition" ma, con programmi più complicati di questo, ciò potrebbe richiedere delle ore. Fortunatamente, make ha parecchi assi nella manica. Ecco un makefile più avanzato:

#un makefile per un programma cobol composto da un singolo file

PROGRAM := addition
LIBS := -lhtcobol -lm
OBJECTS := $(PROGRAM).o

$(PROGRAM):$(OBJECTS)
	gcc -o $(PROGRAM) $(OBJECTS) $(LIBS)

#la regola per tutti i file che terminano con .o
#dipende dai file con stesso prefisso e che finiscono con .s
# $@ è l'obbiettivo
%.o:%.s
	as -o $@ $<

%.s:%.cob
	htcobol $(PROGRAM)

Il Makefile comincia con la definizione di alcune variabili. PROGRAM è il nome del programma da creare, e potete vederne l'uso nella prima regola (la variabile è preceduta da un simbolo del dollaro, e delimitata dalle parentesi). Le LIBS sono semplicemente le librerie che vi servono per compilare il programma. OBJECTS è qualsiasi file-oggetto necessario, in questo caso è soltanto quello che ha lo stesso nome del programma ed ha un .o alla fine, che è quanto è stato dichiarato.

La seconda regola si applica a qualsiasi obbiettivo terminante con .o (%.o), e richiede il file con lo stesso nome ma col suffisso .s (%.s esprime una dipendenza). La variabile automatica $@ corrisponde al nome dell'obbiettivo e $< corrisponde alla prima dipendenza. A questo punto dovreste riuscire ad arrivare all'obiettivo finale.

Se volete adattare questo Makefile ad un altro programma Cobol, tutto quel che dovete fare è una variazione della variabile $PROGRAM.